View Javadoc
1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.common.junit4.Notifier;
23  import org.apache.maven.surefire.junitcore.pc.ParallelComputer;
24  import org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder;
25  import org.apache.maven.surefire.report.ConsoleStream;
26  import org.apache.maven.surefire.testset.TestSetFailedException;
27  import org.apache.maven.surefire.util.TestsToRun;
28  import org.junit.Ignore;
29  import org.junit.runner.Computer;
30  import org.junit.runner.Description;
31  import org.junit.runner.Request;
32  import org.junit.runner.Result;
33  import org.junit.runner.manipulation.Filter;
34  import org.junit.runner.notification.RunListener;
35  import org.junit.runner.notification.StoppedByUserException;
36  
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.Iterator;
40  import java.util.Queue;
41  
42  import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createDescription;
43  import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createIgnored;
44  import static org.apache.maven.surefire.common.junit4.JUnit4RunListener.rethrowAnyTestMechanismFailures;
45  import static org.junit.runner.Computer.serial;
46  import static org.junit.runner.Request.classes;
47  
48  /**
49   * Encapsulates access to JUnitCore
50   *
51   * @author Kristian Rosenvold
52   */
53  final class JUnitCoreWrapper
54  {
55      private final Notifier notifier;
56      private final JUnitCoreParameters jUnitCoreParameters;
57      private final ConsoleStream consoleStream;
58  
59      JUnitCoreWrapper( Notifier notifier, JUnitCoreParameters jUnitCoreParameters, ConsoleStream consoleStream )
60      {
61          this.notifier = notifier;
62          this.jUnitCoreParameters = jUnitCoreParameters;
63          this.consoleStream = consoleStream;
64      }
65  
66      void execute( TestsToRun testsToRun, Filter filter )
67          throws TestSetFailedException
68      {
69          execute( testsToRun, true, Collections.<RunListener>emptyList(), filter );
70      }
71  
72      void execute( TestsToRun testsToRun, Collection<RunListener> listeners, Filter filter )
73              throws TestSetFailedException
74      {
75          execute( testsToRun, false, listeners, filter );
76      }
77  
78      private void execute( TestsToRun testsToRun, boolean useIterated, Collection<RunListener> listeners, Filter filter )
79          throws TestSetFailedException
80      {
81          if ( testsToRun.allowEagerReading() )
82          {
83              executeEager( testsToRun, filter, listeners );
84          }
85          else
86          {
87              executeLazy( testsToRun, useIterated, filter, listeners );
88          }
89      }
90  
91      private JUnitCore createJUnitCore( Notifier notifier, Collection<RunListener> listeners )
92      {
93          JUnitCore junitCore = new JUnitCore();
94  
95          // custom listeners added last
96          notifier.addListeners( listeners );
97  
98          return junitCore;
99      }
100 
101     private void executeEager( TestsToRun testsToRun, Filter filter, Collection<RunListener> listeners )
102         throws TestSetFailedException
103     {
104         JUnitCore junitCore = createJUnitCore( notifier, listeners );
105         Class<?>[] tests = testsToRun.getLocatedClasses();
106         Computer computer = createComputer();
107         createRequestAndRun( filter, computer, junitCore.withReportedTests( tests ), tests );
108     }
109 
110     private void executeLazy( TestsToRun testsToRun, boolean useIterated, Filter filter,
111                               Collection<RunListener> listeners )
112         throws TestSetFailedException
113     {
114         JUnitCore junitCore = createJUnitCore( notifier, listeners );
115         for ( Iterator<Class<?>> it = useIterated ? testsToRun.iterated() : testsToRun.iterator(); it.hasNext(); )
116         {
117             Class<?> clazz = it.next();
118             Computer computer = createComputer();
119             createRequestAndRun( filter, computer, junitCore.withReportedTests( clazz ), clazz );
120         }
121     }
122 
123     private void createRequestAndRun( Filter filter, Computer computer, JUnitCore junitCore, Class<?>... classesToRun )
124         throws TestSetFailedException
125     {
126         Request req = classes( computer, classesToRun );
127         if ( filter != null )
128         {
129             req = new FilteringRequest( req, filter );
130             if ( req.getRunner() == null )
131             {
132                 // nothing to run
133                 return;
134             }
135         }
136 
137         Result run = junitCore.run( req.getRunner() );
138         rethrowAnyTestMechanismFailures( run );
139 
140         if ( computer instanceof ParallelComputer )
141         {
142             String timeoutMessage = ( (ParallelComputer) computer ).describeElapsedTimeout();
143             if ( timeoutMessage.length() != 0 )
144             {
145                 throw new TestSetFailedException( timeoutMessage );
146             }
147         }
148     }
149 
150     private Computer createComputer()
151     {
152         return jUnitCoreParameters.isNoThreading()
153             ? serial()
154             : new ParallelComputerBuilder( consoleStream, jUnitCoreParameters ).buildComputer();
155     }
156 
157     private final class JUnitCore
158         extends org.apache.maven.surefire.junitcore.JUnitCore
159     {
160         JUnitCore()
161         {
162             super( JUnitCoreWrapper.this.notifier );
163         }
164 
165         JUnitCore withReportedTests( Class<?>... tests )
166         {
167             Queue<String> stoppedTests = JUnitCoreWrapper.this.notifier.getRemainingTestClasses();
168             if ( stoppedTests != null )
169             {
170                 for ( Class<?> test : tests )
171                 {
172                     stoppedTests.add( test.getName() );
173                 }
174             }
175             return this;
176         }
177 
178         @Override
179         @SuppressWarnings( "checkstyle:innerassignment" )
180         protected void afterException( Throwable e )
181             throws TestSetFailedException
182         {
183             if ( JUnitCoreWrapper.this.notifier.isFailFast() && e instanceof StoppedByUserException )
184             {
185                 Queue<String> stoppedTests = JUnitCoreWrapper.this.notifier.getRemainingTestClasses();
186                 if ( stoppedTests != null )
187                 {
188                     String reason = e.getClass().getName();
189                     Ignore reasonForSkippedTest = createIgnored( reason );
190                     for ( String clazz; ( clazz = stoppedTests.poll() ) != null; )
191                     {
192                         Description skippedTest = createDescription( clazz, reasonForSkippedTest );
193                         JUnitCoreWrapper.this.notifier.fireTestIgnored( skippedTest );
194                     }
195                 }
196             }
197             else
198             {
199                 super.afterException( e );
200             }
201         }
202 
203         @Override
204         protected void afterFinished()
205         {
206             Queue<String> stoppedTests = JUnitCoreWrapper.this.notifier.getRemainingTestClasses();
207             if ( stoppedTests != null )
208             {
209                 stoppedTests.clear();
210             }
211         }
212     }
213 }